package com.item.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.item.mapper.ComputerusageMapper;
import com.item.pojo.Computer;
import com.item.pojo.Computerusage;
import com.item.pojo.ScheduledFutureHolder;
import com.item.service.ComputerService;
import com.item.mapper.ComputerMapper;
import com.item.mapper.usermapper;
import com.item.task.ComputerBalanceTask;
import com.item.utils.GetLocalDateTimeUtil;
import com.item.utils.RedisUtil;
import com.item.utils.ScheduledTaskUtil;
import com.item.utils.ThreadLocalUtil;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author likaiping
* @description 针对表【computer】的数据库操作Service实现
* @createDate 2024-04-21 12:11:27
*/
@Service
@AllArgsConstructor
public class ComputerServiceImpl extends ServiceImpl<ComputerMapper, Computer>
    implements ComputerService{
    private ComputerMapper computerMapper;
    private ComputerusageMapper computerusageMapper;
    private usermapper usermapper;
    private RedisUtil redisUtil;
    private ScheduledTaskUtil scheduledTaskUtil;
//    private ComputerBalanceTask task = new ComputerBalanceTask();
    @Override
    public List<Computer> findListSearchComputer(BigDecimal price, String detail) {
        return computerMapper.findListSearchComputer(price,detail);
    }

    @Override
    public Map<String, String> insertComputerUsage(String username, String detail) {
        Object isOpenComputer = redisUtil.get(username + "_detail");
        //如果isOpenComputer存在则说明已经上机 则无法打开新机
        if (isOpenComputer != null) {
            throw new RuntimeException("该用户上机，无法使用多台电脑");
        }

        Map<String, String> map = new HashMap<String,String>();
        Long computerId = computerMapper.findIdByDetail(detail);
        Long userId = usermapper.findIdByUsername(username);
        LocalDateTime startTime = LocalDateTime.now();

        map.put("username",username);
        String timeToString = new GetLocalDateTimeUtil().getMyLocalDateTimeToString(startTime);
        map.put("startTime",timeToString);

        //用户可用余额
        BigDecimal balance = computerMapper.selectBalanceByUsername(username);
        balance.setScale(2,RoundingMode.HALF_UP);
        map.put("usableBalance", String.valueOf(balance));

        //计算可用时长
        BigDecimal simplePrice = computerMapper.findPriceByDetail(detail);
        BigDecimal usableTime = balance.divide(simplePrice,2,RoundingMode.HALF_UP);
        map.put("usableTime", String.valueOf(usableTime));

        //存储本次查询余额的时间
        String lastSearchTime = new GetLocalDateTimeUtil().getMyLocalDateTime();
        redisUtil.set("lastSearchTime_"+username,lastSearchTime);
        if (computerusageMapper.selectComputerusageIsOpen(computerId,userId) == null) {
            //可以上机
            computerusageMapper.insertComputerUsage(userId,startTime,computerId);

            //设置每分钟花费的金额累计放在线程变量ThreadLocal中 用来最后下机时查看消耗的金额 然后给用户积分
            redisUtil.set("balanceForPoints_"+username,0);
//            ThreadLocalUtil.set(pointMap);

            //redis中存用户名_电脑信息作为键，电脑信息作为值，用来判断是否已经上机 且只能上一台机
            redisUtil.set(username+"_detail",detail);
            //初始化一个定时任务 用于每秒种执行更改余额
            ComputerBalanceTask task = new ComputerBalanceTask();
            task.setUsername(username);
            task.setSimplePrice(simplePrice);
            task.setComputerMapper(computerMapper);
            task.setRedisUtil(redisUtil);
            //每秒钟一次
//            String cron = "0/1 * * * *  ?";
            //每分钟执行
            String cron = "0 0/1 * * *  ?";
            scheduledTaskUtil.startTask(task, cron);
        }else {
            throw new RuntimeException("用户已使用该电脑");
        }

        return map;
    }

    @Override
    public BigDecimal useEndAndEditComputerUsage(String username, String detail) {
        Long userId = usermapper.findIdByUsername(username);
        System.out.println("detail电脑机型为："+detail);
        Long computerId = computerMapper.findIdByDetail(detail);
        System.out.println("电脑id为：" + computerId);

        //清除redis中的username + "_detail"
        redisUtil.delete(username + "_detail");

        //获取redis中用户花费的金额 并更新积分余额
        if (redisUtil.get("balanceForPoints_" + username) == null) {
            //为空时不给予积分
            //关闭定时任务 停止继续扣费
            HashMap<String, ScheduledFutureHolder> taskMap = scheduledTaskUtil.queryTask();
            if (!taskMap.isEmpty()) {
                String className = taskMap.keySet().iterator().next();
                System.out.println("获取到的定时任务的类名className为："+className);
                scheduledTaskUtil.stopTask(className);
            }else {
                System.out.println("定时任务为空");
            }
            LocalDateTime startTime = computerusageMapper.findStartTimeByUserIdAndComputerId(userId, computerId);
//        String endTime = new GetLocalDateTimeUtil().getMyLocalDateTime();
            LocalDateTime endTime = LocalDateTime.now();
            //使用两个格式化的时间计算出时间差
//        Duration duration = new GetLocalDateTimeUtil().durationForStringTimes(startTime, endTime);
            //使用两个时间计算出时间差
            Duration duration = Duration.between(startTime,endTime);
            //计算出时间差后存储起来为duration，并计算费用cost 时间*单价/分钟
            long hours = duration.toHours();
            long minutes = duration.toMinutes() % 60;
            long seconds = duration.getSeconds() % 60;
            //持续的时间转换为double 单位小时 比如2.26小时
            double durationTime = hours + (double)minutes / 60 + (double)seconds / 3600;
            //保留2位小数
            double roundedTime = Math.round(durationTime * 100.0) / 100.0;
            //每小时的单价
            BigDecimal priceSimple = computerMapper.findPriceByDetail(detail);
            //计算出的费用
            BigDecimal cost = priceSimple.multiply(BigDecimal.valueOf(durationTime));
            System.out.println("计算出准备返回给前端的费用："+cost);
            //返回结果保留两位小数 并使用四舍五入法
            BigDecimal result = cost.setScale(2,BigDecimal.ROUND_HALF_UP);
            //调用mapper将endTime、duration、cost插入computerusage表当中
            boolean isUpdate = computerusageMapper.updateComputerUsage(endTime, roundedTime, result, userId, computerId);

            return result;
        }
        //不为空时则更新积分
        String point = (String) redisUtil.get("balanceForPoints_" + username);
        BigDecimal points = BigDecimal.valueOf((Double.parseDouble(point)));
        computerMapper.updatePointsByUsername(points.intValue(),username);
        System.out.println("本次获得积分为：" + points);
        //清除redis中的余额
        redisUtil.delete("balanceForPoints_" + username);
        //清除线程变量ThreadLocal中的余额
//        ThreadLocalUtil.remove();

        //关闭定时任务 停止继续扣费
        HashMap<String, ScheduledFutureHolder> taskMap = scheduledTaskUtil.queryTask();
        if (!taskMap.isEmpty()) {
            String className = taskMap.keySet().iterator().next();
            System.out.println("获取到的定时任务的类名className为："+className);
            scheduledTaskUtil.stopTask(className);
        }else {
            System.out.println("定时任务为空");
        }

        LocalDateTime startTime = computerusageMapper.findStartTimeByUserIdAndComputerId(userId, computerId);
//        String endTime = new GetLocalDateTimeUtil().getMyLocalDateTime();
        LocalDateTime endTime = LocalDateTime.now();
        //使用两个格式化的时间计算出时间差
//        Duration duration = new GetLocalDateTimeUtil().durationForStringTimes(startTime, endTime);
        //使用两个时间计算出时间差
        Duration duration = Duration.between(startTime,endTime);
        //计算出时间差后存储起来为duration，并计算费用cost 时间*单价/分钟
        long hours = duration.toHours();
        long minutes = duration.toMinutes() % 60;
        long seconds = duration.getSeconds() % 60;
        //持续的时间转换为double 单位小时 比如2.26小时
        double durationTime = hours + (double)minutes / 60 + (double)seconds / 3600;
        //保留2位小数
        double roundedTime = Math.round(durationTime * 100.0) / 100.0;
        //每小时的单价
        BigDecimal priceSimple = computerMapper.findPriceByDetail(detail);
        //计算出的费用
        BigDecimal cost = priceSimple.multiply(BigDecimal.valueOf(durationTime));
        System.out.println("计算出准备返回给前端的费用："+cost);
        //返回结果保留两位小数 并使用四舍五入法
        BigDecimal result = cost.setScale(2,BigDecimal.ROUND_HALF_UP);
        //调用mapper将endTime、duration、cost插入computerusage表当中
        boolean isUpdate = computerusageMapper.updateComputerUsage(endTime, roundedTime, result, userId, computerId);

        return result;
    }

    @Override
    public List<Computerusage> findComputerUsageListByUserId(String username) {
        Long userId = usermapper.findIdByUsername(username);
        List<Computerusage> listUseHistory = computerusageMapper.findComputerUsageListByUserId(userId);
        return listUseHistory;
    }

    @Override
    public List<Computerusage> findHistoryByTimeToTime(String firstTime, String secondTime, String username) {
//        String username = (String) redisUtil.get("username");
        if (username == null) {
            throw new RuntimeException("用户未登录");
        }
        Long userId = usermapper.findIdByUsername(username);
        List<Computerusage> list = computerusageMapper.selectHistoryByTimeToTime(userId, firstTime, secondTime);
        return list;
    }

    @Override
    public Map<String, String> findUsableTimeAndBalance(String username, String detail) {
        HashMap<String, String> map = new HashMap<>();
        GetLocalDateTimeUtil getLocalDateTimeUtil = new GetLocalDateTimeUtil();
        BigDecimal simplePrice = computerMapper.findPriceByDetail(detail);
        //如果单价为空，则说明还没有点击上机，则只查询余额
        if (simplePrice == null) {
            //用户可用余额
            BigDecimal balance = computerMapper.selectBalanceByUsername(username);
            balance.setScale(2,RoundingMode.HALF_UP);
            map.put("usableBalance", String.valueOf(balance));

            return map;
        }
        //本次查询的时间
        String lastSearchTime = getLocalDateTimeUtil.getMyLocalDateTime();
        //获取上一次查询的时间
        String oldLastSearchTime = (String) redisUtil.get("lastSearchTime_"+username);
        if (oldLastSearchTime == null || oldLastSearchTime.equals("")) {
            throw new RuntimeException("还未上机，请先上机");
        }
        //用户可用余额
        BigDecimal balance = computerMapper.selectBalanceByUsername(username);
        balance.setScale(2,RoundingMode.HALF_UP);
        map.put("usableBalance", String.valueOf(balance));
        //计算可用时长
        BigDecimal usableTime = balance.divide(simplePrice,2,RoundingMode.HALF_UP);
        map.put("usableTime", String.valueOf(usableTime));

        //设置本次查询时间
        redisUtil.set("lastSearchTime_"+username,lastSearchTime);

        return map;
    }

    @Override
    public Boolean addComputer(Computer computer) {
        return computerMapper.insertComputer(computer.getDetail(), computer.getPrice());
    }

    @Override
    public boolean removeComputer(Integer id) {
        return computerMapper.deleteByDetailBoolean(id);
    }

    @Override
    public boolean editComputer(Computer computer) {
        return computerMapper.updateComputer(computer.getDetail(),computer.getPrice(),computer.getId());
    }
}




